﻿using System;
using System.Collections.Generic;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Graphics;
using System.Linq;

namespace Babylon.Toolbox.ModelBuilding
{
    public class MeshContent<T> : MeshContent where T : struct, IVertexType
    {
        List<T> _stagingVertices = new List<T>();

        public MeshContent(ModelContent parent, bool optimize, bool generatePickingInformations)
            : base(parent, optimize, generatePickingInformations, new T().VertexDeclaration)
        {

        }

        public void ProcessVertices(Action<IList<T>, IList<int>> beforeBuffersGenerationProcess = null)
        {
            if (Optimize)
            {
                for (int indicesIndex = 0; indicesIndex < StagingIndices.Count; indicesIndex++)
                {
                    StagingIndices[indicesIndex] = IndicesHashTable[StagingIndices[indicesIndex]];
                }
                RegisteredVertices.Clear();
                IndicesHashTable.Clear();
            }

            if (beforeBuffersGenerationProcess != null)
            {
                beforeBuffersGenerationProcess(_stagingVertices, StagingIndices);
            }

            // Vertex buffer
            VerticesCount = _stagingVertices.Count;
            ProcessParts();
        }

        public void AddVertex(T vertex)
        {
            if (!Optimize)
            {
                _stagingVertices.Add(vertex);
                return;
            }

            string hash = vertex.ToString();
            int index;

            if (!RegisteredVertices.TryGetValue(hash, out index))
            {
                _stagingVertices.Add(vertex);

                IndicesHashTable.Add(_stagingVertices.Count - 1);
                RegisteredVertices.Add(hash, _stagingVertices.Count - 1);
            }
            else
            {
                IndicesHashTable.Add(index);
            }
        }

        internal override int AppendToVertexBuffer(VertexBuffer vertexBuffer, int vertexBufferOffset, out BoundingSphere boundingSphere, out Vector3[] positions)
        {
            int stride = _stagingVertices[0].VertexDeclaration.VertexStride;
            T[] array = _stagingVertices.ToArray();
            vertexBuffer.SetData(vertexBufferOffset, array, 0, _stagingVertices.Count, stride);

            positions = array.Select(v => v.GetPosition()).ToArray();
            boundingSphere = BoundingSphere.CreateFromPoints(positions);

            vertexBufferOffset += _stagingVertices.Count * stride;
            _stagingVertices = null;

            return vertexBufferOffset;
        }

    }
}
